package org.ym.tools;

import org.apache.commons.lang3.StringUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
 * @author ym
 * @date 2022-06-09 13:42:36
 */
public class StreamTool {

    public static final int BYTE_CACHE_MAX = 4096;

    private StreamTool() {
    }

    public static final String SLASH = "/";

    /**
     * UTF-8字符集模式读取jar包内文件文本内容
     *
     * @param classFilePath 文件的classpath
     * @return 数据文本
     * @throws IOException IO错误
     */
    public static String readJarFileAsText(String classFilePath) throws IOException {
        return readJarFileAsText(classFilePath, StandardCharsets.UTF_8);
    }

    /**
     * 读取jar包文件文本内容，返回字符串
     *
     * @param classFilePath 文件的classpath
     * @param charset       字符集
     * @return 数据文本
     * @throws IOException IO错误
     */
    public static String readJarFileAsText(String classFilePath, Charset charset) throws IOException {
        String content;
        try (ByteArrayOutputStream byteArrayOutputStream = readJarFileAsByteArrayStream(classFilePath)) {
            if (byteArrayOutputStream != null) {
                content = byteArrayOutputStream.toString(charset.name());
            } else {
                content = null;
            }
        }
        return content;
    }

    /**
     * 读取jar包文件文本内容，返回二进制数据
     *
     * @param classFilePath 文件的classpath
     * @return 二进制数据
     * @throws IOException IO错误
     */
    public static byte[] readJarFileAsByte(String classFilePath) throws IOException {
        byte[] bytes;
        try (ByteArrayOutputStream byteArrayOutputStream = readJarFileAsByteArrayStream(classFilePath)) {
            if (byteArrayOutputStream != null) {
                bytes = byteArrayOutputStream.toByteArray();
            } else {
                bytes = null;
            }
        }
        return bytes;
    }

    /**
     * 读取jar包文件文本内容，返回ByteArrayOutputStream流,最后需要关闭流
     *
     * @param classFilePath 文件的classpath
     * @return ByteArrayOutputStream流
     * @throws IOException IO错误
     */
    public static ByteArrayOutputStream readJarFileAsByteArrayStream(String classFilePath) throws IOException {
        try (InputStream inputStream = readJarFile(classFilePath)) {
            return changeByteArrayOutputStream(inputStream);
        }
    }

    /**
     * 读取jar包文件文本内容，返回InputStream流,最后需要关闭流
     *
     * @param classFilePath 文件的classpath,以"/"开头
     * @return InputStream流
     */
    public static InputStream readJarFile(String classFilePath) {
        if (StringUtils.isNotBlank(classFilePath)) {
            if (!StringUtils.startsWith(classFilePath, SLASH)) {
                classFilePath = StringTool.concatStr(SLASH, classFilePath);
            }
            return StreamTool.class.getResourceAsStream(classFilePath);
        } else {
            return null;
        }
    }

    /**
     * 读取jar文件，输出到HttpServletResponse的输出流里
     *
     * @param response 输出
     * @param classFilePath 文件路径
     */
    public static void setResponseOutPutStreamFromJarFile(HttpServletResponse response, String classFilePath) throws IOException {
        try (InputStream inputStream = readJarFile(classFilePath); OutputStream outputStream = response.getOutputStream()) {
            setOutPutStreamFromInputStream(outputStream,inputStream);
        }
    }

    /**
     * UTF-8字符集模式读取系统文件内容
     *
     * @param commonFilePath 文件的物理全路径
     * @return 数据文本
     * @throws IOException IO错误
     */
    public static String readCommonFileAsText(String commonFilePath) throws IOException {
        return readJarFileAsText(commonFilePath, StandardCharsets.UTF_8);
    }

    /**
     * 读取系统文件内容，返回字符串
     *
     * @param commonFilePath 文件的物理全路径
     * @param charset       字符集
     * @return 数据文本
     * @throws IOException IO错误
     */
    public static String readCommonFileAsText(String commonFilePath, Charset charset) throws IOException {
        String content;
        try (ByteArrayOutputStream byteArrayOutputStream = readCommonFileAsByteArrayStream(commonFilePath)) {
            if (byteArrayOutputStream != null) {
                content = byteArrayOutputStream.toString(charset.name());
            } else {
                content = null;
            }
        }
        return content;
    }

    /**
     * 读取系统文件内容，返回字节数组
     *
     * @param commonFilePath 文件的物理全路径
     * @return 二进制数据
     * @throws IOException IO错误
     */
    public static byte[] readCommonFileAsByte(String commonFilePath) throws IOException {
        byte[] bytes;
        try (ByteArrayOutputStream byteArrayOutputStream = readCommonFileAsByteArrayStream(commonFilePath)) {
            if (byteArrayOutputStream != null) {
                bytes = byteArrayOutputStream.toByteArray();
            } else {
                bytes = null;
            }
        }
        return bytes;
    }

    /**
     * 读取系统文件内容，返回ByteArrayOutputStream流,最后需要关闭流
     *
     * @param commonFilePath 文件的物理全路径
     * @return ByteArrayOutputStream流
     * @throws IOException IO错误
     */
    public static ByteArrayOutputStream readCommonFileAsByteArrayStream(String commonFilePath) throws IOException {
        try (InputStream inputStream = readCommonFile(commonFilePath)) {
            return changeByteArrayOutputStream(inputStream);
        }
    }

    /**
     * 读取系统文件内容，返回InputStream流,最后需要关闭流
     *
     * @param commonFilePath 文件的物理全路径
     * @return InputStream流
     */
    public static InputStream readCommonFile(String commonFilePath) throws FileNotFoundException {
        if (StringUtils.isNotBlank(commonFilePath)) {
            Path path = Paths.get(commonFilePath);
            if (path.toFile().canRead()) {
                return new FileInputStream(path.toFile());
            } else {
                return null;
            }
        } else {
            return null;
        }
    }

    /**
     * 读取jar文件，输出到HttpServletResponse的输出流里
     *
     * @param response 输出
     * @param commonFilePath 文件的物理全路径
     */
    public static void setResponseOutPutStreamFromCommonFile(HttpServletResponse response, String commonFilePath) throws IOException {
        try (InputStream inputStream = readCommonFile(commonFilePath); OutputStream outputStream = response.getOutputStream()) {
            setOutPutStreamFromInputStream(outputStream,inputStream);
        }
    }

    /**
     * 转换输入流为字节输出流
     * @param inputStream 输入流,结束后需关闭流
     * @return 输出流，结束后需关闭流
     * @throws IOException 报错
     */
    public static ByteArrayOutputStream changeByteArrayOutputStream(InputStream inputStream) throws IOException {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        if (inputStream != null) {
            setOutPutStreamFromInputStream(byteArrayOutputStream,inputStream);
        } else {
            byteArrayOutputStream = null;
        }
        return byteArrayOutputStream;
    }

    /**
     * 向response写入数据
     * @param outputStream 输出流
     * @param inputStream 输入流
     */
    public static void setOutPutStreamFromInputStream(OutputStream outputStream,InputStream inputStream) throws IOException {
        if(outputStream != null && inputStream != null){
            byte[] bytes = new byte[BYTE_CACHE_MAX];
            int length;
            while ((length = inputStream.read(bytes)) > 0) {
                outputStream.write(bytes, 0, length);
            }
            outputStream.flush();
        }
    }

    /**
     * 输出到HttpServletResponse的输出流里
     *
     * @param response 输出
     * @param text 内容
     */
    public static void writeResponseStream(HttpServletResponse response, String text) throws IOException {
        if(StringUtils.isNotBlank(text)) {
            try (InputStream inputStream = new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8)); OutputStream outputStream = response.getOutputStream()) {
                setOutPutStreamFromInputStream(outputStream, inputStream);
                response.setContentType("text/html;charset=utf-8");
                response.setCharacterEncoding(StandardCharsets.UTF_8.name());
            }
        }
    }

    /**
     * 写入文件
     * @param source 流
     * @param filePath 文件，需先创建
     * @return 写入字节数
     * @throws IOException
     */
    public static long writeFile(InputStream source,Path filePath) throws IOException {
        try(InputStream inputStream = source;FileOutputStream fileOutputStream = new FileOutputStream(filePath.toFile())){
            byte[] bytes = new byte[BYTE_CACHE_MAX];
            int length;
            long size = 0;
            while ((length = inputStream.read(bytes)) > 0) {
                size += length;
                fileOutputStream.write(bytes, 0, length);
            }
            return size;
        }
    }
}
